package com.jacobson.core.widget.rv

import android.graphics.Canvas
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.ItemTouchHelper.*
import androidx.recyclerview.widget.RecyclerView
import com.jacobson.core.widget.logger.LoggerFactory

/**
 * ================================================
 *
 *  @author Wucz on 2018-09-05 11:18
 * ================================================
 */

class Drag2RemoveTouchCallback : ItemTouchHelper.Callback() {
    private val logger = LoggerFactory.getLogger()
    private var lastSelectedViewHolder: RecyclerView.ViewHolder? = null
    private var removeView: View? = null
    private val dragRegion = Rect()
    private val removeRegion = Rect()
    /**
     * 是否需要判断删除控件
     */
    private var isDragRemoveRelease = false

    private var isDraggableDecider: ((position: Int, itemCount: Int) -> Boolean) =
        { position, itemCount ->
            position != itemCount - 1
        }
    private var canDropOverDecider: ((currentPosition: Int, targetPosition: Int, itemCount: Int) -> Boolean) =
        { _, targetPosition, itemCount ->
            targetPosition != itemCount - 1
        }

    fun setRemoveView(removeView: View) {
        this.removeView = removeView
    }

    /**
     * 这个是用来设置用户可以对 viewHolder进行什么操作，推荐用makeMovementFlags(int dragFlags, int swipeFlags)来处理
     */
    override fun getMovementFlags(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder
    ): Int {
        val adapterPosition = viewHolder.adapterPosition
        val itemCount = recyclerView.adapter?.itemCount ?: -1
        if (adapterPosition == -1 || itemCount == -1) {
            return 0
        }
        if (!isDraggableDecider.invoke(adapterPosition, itemCount)) {
            //该位置是否禁止拖拽，默认最后一个禁止拖拽
            return 0
        }
        return makeMovementFlags(LEFT or RIGHT or UP or DOWN, LEFT)
    }

    /**
     * 这个是拖拽的回调
     * @param recyclerView
     * @param viewHolder  这个是我们拖拽中的ViewHolder
     * @param target      这个是离我们拖拽ViewHolder最近的ViewHolder，也就是我们松手后需要替换的ViewHolder
     * @return  返回true的话 我们已经做好相关操作了，false就我们没做啥操作
     */
    override fun onMove(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        (recyclerView.adapter as? DraggableAdapter)?.run {
            val targetPosition = target.adapterPosition
            val sourcePosition = viewHolder.adapterPosition
            if (sourcePosition != -1 && targetPosition != -1) {
                return onDragSwap(sourcePosition, targetPosition).apply {
                    recyclerView.adapter?.notifyItemMoved(sourcePosition, targetPosition)
                }
            }
        }
        return false
    }

    /**
     * 用来判断 target是否可以被替换
     * @param recyclerView
     * @param current
     * @param target
     * @return  true :target可以被current替换
     *          false：不可以
     */
    override fun canDropOver(
        recyclerView: RecyclerView,
        current: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        val currentPosition = current.adapterPosition
        val targetPosition = target.adapterPosition
        val itemCount = recyclerView.adapter?.itemCount ?: -1
        if (currentPosition == -1 || targetPosition == -1 || itemCount == -1) {
            return false
        }
        if (!canDropOverDecider.invoke(currentPosition, targetPosition, itemCount)) {
            //该位置是否不允许被替换
            return false
        }
        return super.canDropOver(recyclerView, current, target)
    }

    /**
     * 侧滑
     */
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit

    /**
     * 我们不需要滑动删除，所以返回false
     */
    override fun isItemViewSwipeEnabled(): Boolean = false

    /**
     * 手指松开的时候
     */
    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        super.clearView(recyclerView, viewHolder)
        logger.d("ClearView")
        //完成拖动后刷新适配器，这样拖动后删除就不会错乱
        try {
            recyclerView.adapter?.notifyDataSetChanged()
        } catch (exception: Exception) {
            exception.printStackTrace()
        }
    }

    override fun onChildDraw(
        c: Canvas,
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        dX: Float,
        dY: Float,
        actionState: Int,
        isCurrentlyActive: Boolean
    ) {
        viewHolder.itemView.run {
            removeView?.let {
                calcRegion(this, true)
                calcRegion(it, false)
                if (dragRegion.intersect(removeRegion)) {
                    onDragRemoveListener?.enterRemoveRegion()
                } else {
                    onDragRemoveListener?.outerRemoveRegion()
                }
            }
            onDragRemoveListener?.let {
                if (isDragRemoveRelease) {
                    logger.d("onChildDraw: $actionState")
                    isDragRemoveRelease = false
                    val position = viewHolder.adapterPosition
                    //删除
                    recyclerView.adapter?.takeIf { adapter ->
                        it.isEnterState() && adapter is DraggableAdapter && adapter.onDragRemove(
                            position
                        )
                    }?.run {
                        viewHolder.itemView.visibility = View.INVISIBLE
                        notifyItemRemoved(position)
                        notifyItemRangeChanged(position, itemCount)
                    }
                    it.endDrag()
                }
            }
        }
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
    }

    private fun calcRegion(view: View, isDrag: Boolean) {
        val location = IntArray(2)
        view.getLocationOnScreen(location)
        (if (isDrag) dragRegion else removeRegion).set(
            location[0], location[1], location[0] + view.width, location[1] + view.height
        )
    }

    /**
     * 用户长按后，会触发拖拽的选中效果，viewHolder就是当前的选中
     */
    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
        super.onSelectedChanged(viewHolder, actionState)
        logger.d("onSelectedChanged: viewHolder = $viewHolder, actionState = $actionState")
        //如果状态为拖拽，说明选中了
        when (actionState) {
            ACTION_STATE_DRAG -> {
                isDragRemoveRelease = false
                viewHolder?.itemView?.scaleX = 1.05f
                viewHolder?.itemView?.scaleY = 1.05f
                lastSelectedViewHolder = viewHolder
                //开始拖拽
                onDragRemoveListener?.startDrag()
            }
            ACTION_STATE_IDLE -> {
                lastSelectedViewHolder?.itemView?.scaleX = 1.0f
                lastSelectedViewHolder?.itemView?.scaleY = 1.0f
                lastSelectedViewHolder = null
                //释放
                isDragRemoveRelease = true

            }
        }
    }

    private var onDragRemoveListener: OnDragRemoveListener? = null
    fun setOnDragRemoveListener(listener: OnDragRemoveListener) {
        this.onDragRemoveListener = listener
    }

    abstract class OnDragRemoveListener {
        private var isEnterState: Boolean = false

        abstract fun onDragState(dragState: Boolean)
        abstract fun onEnterStateChanged(isEnter: Boolean)

        fun isEnterState(): Boolean = isEnterState

        fun startDrag() {
            isEnterState = false
            onEnterStateChanged(false)
            onDragState(true)
        }

        fun endDrag() {
            isEnterState = false
            onEnterStateChanged(false)
            onDragState(false)
        }

        fun enterRemoveRegion() {
            if (!isEnterState) {
                isEnterState = true
                onEnterStateChanged(true)
            }
        }

        fun outerRemoveRegion() {
            if (isEnterState) {
                isEnterState = false
                onEnterStateChanged(false)
            }
        }
    }
}